﻿#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "simnand.h"
#include "fflags.h"

enum {
    FFLAGS_HELP = 1,
    FFLAGS_CHANNEL,
    FFLAGS_DIE,
    FFLAGS_PLANE,
    FFLAGS_BLOCK,
    FFLAGS_PAGE,
    FFLAGS_SECTOR,
    FFLAGS_PATH,
    FFLAGS_IP,
};

ff_defArg(cmdline, true)
    ff_argRule('h', help,    not,  FFLAGS_HELP)
    ff_argRule('c', channel, must, FFLAGS_CHANNEL)
    ff_argRule('d', die,     must, FFLAGS_DIE)
    ff_argRule('p', plane,   must, FFLAGS_PLANE)
    ff_argRule('b', block,   must, FFLAGS_BLOCK)
    ff_argRule('g', page,    must, FFLAGS_PAGE)
    ff_argRule('s', sector,  must, FFLAGS_SECTOR)
    ff_argRule('t', path,    must, FFLAGS_PATH)
    ff_argRule('i', ip,      must, FFLAGS_IP)
ff_endArg(cmdline, true);

ff_childList(sys, ff_child(cmdline));

static void help()
{
    printf("\nhelp info:\n"
        "    -h, --help \n"
        "    -c, --channel how many channel supported\n"
        "    -d, --die     how many dies in device\n"
        "    -p, --plane   how many planes in device\n"
        "    -b, --block   how many blocks in device\n"
        "    -g, --page    page size in bytes\n"
        "    -s, --sector  sector size\n"
        "    -t, --path    channel datas saved in this path\n"
        "    -i, --ip      socket ip address\n"
        "\n"
    );
}


static struct simnand_device g_simnand = {
    .channelcnt = 1,
    .diecnt = DIE_SIZE,
    .planecnt = BANK_SIZE,
    .blockcnt = BLOCK_SIZE,
    .pagesize = PAGE_SIZE,
    .sectorsize = SECTOR_SIZE,
    .port = DEFAULT_PORT,
    .path = DEFAULT_PATH,
    .ip = DEFAULT_IP,
};

int parse_cmdline(int argc, char **argv)
{
    ff_FFlags *ff = ff_initFFlags(argc, argv, true, true, stderr, sys);
    if (ff == NULL)
        return 1;

    char *text = NULL;
    int mark = 0;

    while (1) {
        mark = ff_getopt(&text, ff);
        switch (mark) {
            case FFLAGS_HELP:
                help();
                break;
            case FFLAGS_CHANNEL:
                g_simnand.channelcnt = atoi(text);
                printf("channel count: %d\n", g_simnand.channelcnt);
                break;
            case FFLAGS_DIE:
                g_simnand.diecnt = atoi(text);
                printf("    die count: %d\n", g_simnand.diecnt);
                break;
            case FFLAGS_PLANE:
                g_simnand.planecnt = atoi(text);
                printf("  plane count: %d\n", g_simnand.planecnt);
                break;
            case FFLAGS_BLOCK:
                g_simnand.blockcnt = atoi(text);
                printf("  block count: %d\n", g_simnand.blockcnt);
                break;
            case FFLAGS_PAGE:
                g_simnand.pagesize = atoi(text);
                printf("    page size: %d\n", g_simnand.pagesize);
                break;
            case FFLAGS_SECTOR:
                g_simnand.sectorsize = atoi(text);
                printf("  sector size: %d\n", g_simnand.sectorsize);
                break;
            case FFLAGS_PATH:
                snprintf(g_simnand.path, MAX_PATH_LENGTH, "%s", text);
                printf("    save path: %s\n", g_simnand.path);
                break;
            case FFLAGS_IP:
                snprintf(g_simnand.ip, MAX_IP_LENGTH, "%s", text);
                printf("   ip address: %s\n", g_simnand.ip);
                break;
            default:
                goto out;
        }
    }

out:
    ff_freeFFlags(ff);

    return 0;
}


static struct simnand_inst simnand_inst_param[MAX_CHANNEL_COUNT] =
{
    {
        .chid = CHANNEL0,
    },
    {
        .chid = CHANNEL1,
    },
    {
        .chid = CHANNEL2,
    },
    {
        .chid = CHANNEL3,
    },
};


int main(int argc, char* argv[])
{
    int err;

    parse_cmdline(argc, argv);

    printids("main thread: ");

    for (int i=CHANNEL0; i<g_simnand.channelcnt; i++) {
        simnand_inst_param[i].chid = i;
        //snprintf(simnand_inst_param[i].pchpath, strlen(g_simnand.path), "%s/channel%d", g_simnand.path, i);
        sprintf(simnand_inst_param[i].pchpath, "%s/channel%d", g_simnand.path, i);
    printf("###%s,%s\n", g_simnand.path, simnand_inst_param[i].pchpath);
        simnand_inst_param[i].portnum = g_simnand.port + i;
        simnand_inst_param[i].ip = g_simnand.ip;

        err = pthread_create(&g_simnand.pid[i], NULL, simnand_inst_server, &simnand_inst_param[i]);
        if (err != 0) {
            fprintf(stdout, "channel %d Can't create thread: %s\n", i, strerror(err));
        }

        fprintf(stdout, "channel %d create thread %ld\n", i, g_simnand.pid[i]);

    }

    for (int i=0; i<g_simnand.channelcnt; i++) {
        if (g_simnand.pid[i] != 0)
            pthread_join(g_simnand.pid[i], NULL);
    }

//    register_socket_server(&channelparam);

    return 0;
}

